
#include "SSHChannel.h"

/** Constructor for the SSH channel. */
SSHChannel::SSHChannel(SSHClient &itclient) : tclient(&itclient)
{
   apr_status_t status = apr_pool_create(&imp, itclient.getMemoryPool());
   CheckAPRError(status);
   if (status != APR_SUCCESS) imp = NULL;
}

/** Future destructor wrapper for the stop channel. This assumes that
 * the argument immediately after the SSHChannel derivative this
 * pointer is the LIBSSH2_CHANNEL pointer that needs flushing and
 * closing.
 * 
 * @param future_arguments The arguments list from the APRFuture
 * class. */
void *SSHChannel::stopChannelFuture(std::vector<void *> *future_arguments)
{
   SSHChannel::stopChannel((SSHChannel *)(((void **)&(future_arguments->at(0)))[1]), (LIBSSH2_CHANNEL *)(((void **)&(future_arguments->at(0)))[2]));
   return NULL;
}

/** Stop channel.
 * 
 * @param sshchan The SSH channel class pointer.
 * 
 * @param tchannel The channel to stop. */
void SSHChannel::stopChannel(SSHChannel *sshchan, LIBSSH2_CHANNEL *tchannel)
{
   SSHClient *stclient = sshchan->tclient;
   int ssh_status = 0;
   if (tchannel != NULL)
   {
      int timeout = 1;
      while ((ssh_status = libssh2_channel_handle_extended_data2(tchannel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE)) ==
         LIBSSH2_ERROR_EAGAIN)
      {
         timeout <<= 1;
         timeout = (timeout > SSH_TIMEOUT_EAGAIN) ? SSH_TIMEOUT_EAGAIN : timeout;
         apr_sleep(timeout);
      }
      eCheckLibSSH2Error(stclient, ssh_status);
      timeout = 1;
      while ((ssh_status = libssh2_channel_flush_ex(tchannel, LIBSSH2_CHANNEL_FLUSH_ALL)) == LIBSSH2_ERROR_EAGAIN)
      {
         timeout <<= 1;
         timeout = (timeout > SSH_TIMEOUT_EAGAIN) ? SSH_TIMEOUT_EAGAIN : timeout;
         apr_sleep(timeout);
      }
      //eCheckLibSSH2Error(stclient, ssh_status);
      timeout = 1;
      while ((ssh_status = libssh2_channel_close(tchannel)) == LIBSSH2_ERROR_EAGAIN)
      {
         timeout <<= 1;
         timeout = (timeout > SSH_TIMEOUT_EAGAIN) ? SSH_TIMEOUT_EAGAIN : timeout;
         apr_sleep(timeout);
      }
      eCheckLibSSH2Error(stclient, ssh_status);
      timeout = 1;
      while ((ssh_status = libssh2_channel_wait_closed(tchannel)) == LIBSSH2_ERROR_EAGAIN)
      {
         timeout <<= 1;
         timeout = (timeout > SSH_TIMEOUT_EAGAIN) ? SSH_TIMEOUT_EAGAIN : timeout;
         apr_sleep(timeout);
      }
      if (ssh_status != -34)
         eCheckLibSSH2Error(stclient, ssh_status);
      timeout = 1;
      while ((ssh_status = libssh2_channel_free(tchannel)) == LIBSSH2_ERROR_EAGAIN)
      {
         timeout <<= 1;
         timeout = (timeout > SSH_TIMEOUT_EAGAIN) ? SSH_TIMEOUT_EAGAIN : timeout;
         apr_sleep(timeout);
      }
   }
}

/** Destructor. */
SSHChannel::~SSHChannel()
{
   if (imp)
   {
      apr_pool_clear(imp);
      apr_pool_destroy(imp);
   }
   imp = NULL;
}
